#!/usr/bin/env python
# $Id: apreconf.py df54dec975f4 2012/09/09 20:22:40 pgurumur $
# Copyright (c) 2012 Prabhu Gurumurthy <pgurumur@gmail.com>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#

__version__  = "$Revision: df54dec975f4 $"
__author__   = "$Author: pgurumur $"
__modified__ = "$Date: 2012-09-09 20:22:40Z $"

import ConfigParser
import optparse
import os
import sys

from Cheetah.Template import Template

from venya.lib import cmdparser
from venya.lib import exception
from venya.lib import ip
from venya.lib import sql
from venya.lib import stdlib

class apreconf(cmdparser.GetOpt):
   option_list = (
         optparse.make_option("-a", "--ap", type = "str",
            help = "AP new IPv4 address", dest = "ap"),
         optparse.make_option("-c", "--config", type = "str",
            help = "DB configuration file, default: sql.cfg",
            default = "sql.cfg", dest = "config"),
         optparse.make_option("-i", "--ip", type = "str",
            help = "New IP (RFC2893) address for the AP reconfig", dest = "ip"),
         optparse.make_option("-m", "--map", type = "str",
            help = "New VPN map for the AP reconfig", dest = "vpn"),
         optparse.make_option("-t", "--template", type = "str",
            help = "Tunnel template to use, default: apreconf.tmpl",
            default = "apreconf.tmpl", dest = "template"),
         optparse.make_option("-A", "--aptemplate", type = "str",
            help = "AP configuration template to use: default ap.tmpl",
            default = "ap.tmpl", dest = "aptemplate")
   ) + cmdparser.GetOpt.option_list

   def __init__(self, **kwargs):
      super(apreconf, self).__init__(**kwargs)
      self._sql = None
      self._rfc2893 = None
      self._tmpl = None
      self._aptmpl = None

   def ip2ahex(self, ipaddr):
      retval = None
      if ipaddr:
         iplen = len(ipaddr)
         maxlen = 16
         for ix in ipaddr:
            retval += ":" + hex(ord(ix))
   
         for ix in xrange((maxlen - iplen)):
            retval += ":0x0"

      return retval

   def GetRecord(self, MacAddr):
      record = None
      if MacAddr:
         record = [value for value in self._rfc2893.q.filter(
            self._rfc2893.remote_mac_addr == str(MacAddr)).all()]
         if record:
            record = record[0]

      return record
      
   def printconfig(self, macaddr, ipaddr = None, vpnmap = None, apaddr = None):
      for mac in macaddr:
         if ipaddr:
            updated = self._rfc2893.SQLUpdate("remote_mac_addr", macaddr,
                  local_ipv4_addr = str(ipaddr))
            if updated:
               print("AP: %s updated with VPN peer: %s" %(macaddr, ipaddr))

         if vpnmap:
            updated = self._rfc2893.SQLUpdate("remote_mac_addr", macaddr,
                  crypto_transform_name = str(vpnmap))
            if updated:
               print("AP: %s updated with VPN map: %s" %(macaddr, vpnmap))

         if apaddr:
            updated = self._rfc2893.SQLUpdate("remote_mac_addr", macaddr,
                  remote_ipv4_addr = str(apaddr))
            if updated:
               print("AP: %s updated with IP address: %s" %(macaddr, apaddr))

         record = self.GetRecord(mac)
         config = "cisco-%s.cfg" %"".join(mac.split(":"))
         apconfig = "ap-%s.cfg" %"".join(main.split(":"))
         cfgdict = {}
         if record:
            cfgdict["local"] = record[6]
            cfgdict["peer"] = record[8]
            cfgdict["map"] = record[25]
            cfgdict["mapidx"] = record[24]
            cfgdict["mac"] = record[4]
            cfgdict["inspi"] = record[13]
            cfgdict["outspi"] = record[14]
            cfgdict["incipher"] = record[18]
            cfgdict["outcipher"] = record[19]
            cfgdict["inauth"] = record[20]
            cfgdict["outauth"] = record[21]
            cfgdict["acl"] = record[-1]
            cfgdict["tidx"] = record[11]
            cfgdict["customer"] = record[2]
            cfgdict["aptype"] = record[3]
            ix = None

            try:
               ix = ip.ip("%s/64" %record[7])
            except exception.IPError as err:
               print(err)
               continue
            else:
               cfgdict["tunaddr"] = str(ix)

            try:
               ix = ip.ip("%s/64" %record[10])
            except exception.IPError as err:
               print(err)
               continue
            else:
               apcfg["apaddr"] = str(ix)
               cfgdict["rfaddr"] = "%s/64" %ix[0]

            apcfg["apip"] = record[8]
            apcfg["rfcip"] = record[6]

            fh = None
            temp = Template(file = self._tmpl, searchList = [cfgdict])
            try:
               if temp:
                  fh = open(config, "w")
            except IOError as err:
               print(err)
               continue
            else:
               fh.write(str(temp))
               fh.close()
               fh = None
               temp = None

            temp = Template(file = self._aptmpl, searchList = [apcfg])
            try:
               if temp:
                  fh = open(apconfig, "w")
            except IOError as err:
               print(err)
               continue
            else:
               fh.write(str(temp))
               fh.close()
               fh = None
               temp = None

   def handle(self):
      (options, args) = self.parse()
      macaddr = []
      try:
         macaddr = args[1:]
      except IndexError:
         self.error("need one or more mac addresses!")

      self._tmpl = options.template
      self._aptmpl = options.aptemplate
      dbName = None
      if options.config:
         try:
            self._cfg = config.Lexer(options.config)
         except exception.LexerError as err:
            self.error(err)
         else:
            dbName = self._cfg.RFC2893

      try:
         if dbName:
            self._netdb = sql.mysql(dbName.dbname,
                  dbName.dbhost, dbName.dbuser, dbName.dbpass)
      except exception.SQLError as err:
         self.error(err)

      ipaddr = None
      vpnmap = None
      apaddr = None

      if options.vpn:
         vpnmap = options.vpn

      if options.ip:
         try:
            ipaddr = ip.ip(options.ip)
         except exception.IPError as err:
            self.error(err)

         if ipaddr.size() > 1:
            self.error("got network instead of IP address")

      if options.ap:
         try:
            apaddr = ip.ip(options.ap)
         except exception.IPError as err:
            self.error(err)

         if apaddr.size() > 1:
            self.error("got network instead of IP address")

      self._rfc2893 = self._sql.rfc2893
      self.printconfig(macaddr, ipaddr, vpnmap, apaddr)

if __name__ == "__main__":
   apconf = None
   try:
      apconf = apreconf(version = 1.0, args = sys.argv, usage = "mac address")
      if len(apconf) <= 1:
         apconf.printhelp()
      else:
         apconf.handle()
   except exception.GetOptError as err:
      print(err)
      sys.exit(1)

